package com.hjb.service.gateway.baofoo.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.hjb.service.domain.recharge.BankCardBin;
import com.hjb.service.domain.recharge.BankCardBinExample;
import com.hjb.service.gateway.baofoo.BaoFooPayService;
import com.hjb.service.gateway.baofoo.domain.TransConstant;
import com.hjb.service.gateway.baofoo.domain.TransContent;
import com.hjb.service.gateway.baofoo.domain.request.RequestParams;
import com.hjb.service.gateway.baofoo.domain.request.TransReqBF0040001;
import com.hjb.service.gateway.baofoo.domain.response.TransRespBF0040001;
import com.hjb.service.gateway.baofoo.util.RsaCodingUtil;
import com.hjb.service.gateway.baofoo.util.SecurityUtil;
import com.hjb.service.gateway.baofoo.util.SimpleHttpResponse;
import com.hjb.service.gateway.baofoo.util.authpay.HttpsUtil;
import com.hjb.service.gateway.baofoo.util.proxypay.BaofooClient;
import com.hjb.service.mapper.BankCardBinMapper;
import com.hjb.service.utils.DateUtil;
import com.hjb.service.utils.JXMConvertUtil;
import com.hjb.service.utils.MapToXml;
import com.hjb.service.utils.MapUtil;

import net.sf.json.JSONObject;

/**
 * Created by gy on 2017/7/28.
 * 宝付接口实现
 */
@Service("baoFooService")
public class BaoFooPayServiceImpl implements BaoFooPayService{

	private Logger log = LoggerFactory.getLogger(getClass());
	
	@Autowired
	private BankCardBinMapper bankCardBinMapper;
	
//	@Autowired
//	private BaofooProperties baofooProperties;
	@Value("${baofoo.pfxFile}")
	private String keyStorePath;//商户私钥
	@Value("${baofoo.pfxPassword}")
	private String keyStorePassword;//商户私钥
	@Value("${baofoo.cerFile}")
	private String pub_key;//宝付公钥
	@Value("${baofoo.proxypayUrl}")
	private String proxypayUrl;//提现
	@Value("${baofoo.merchId}")
	private String memberId;//商户号
	@Value("${baofoo.terminalId}")
	private String terminalId;//终端号
	@Value("${baofoo.authpayUrl}")
	private String authpayUrl;//业务接口(根据业务类型,包括绑卡，预支付，确认支付)

	/* 
	 * 代付（代发）
	 */
	@Override
	public Map<String, Object> proxyPay(TransReqBF0040001 transReqBF0040001) {
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			String dataType = TransConstant.data_type_xml; // 数据类型 xml/json
			TransContent<TransReqBF0040001> transContent = new TransContent<TransReqBF0040001>(dataType);
			List<TransReqBF0040001> trans_reqDatas = new ArrayList<TransReqBF0040001>();
			trans_reqDatas.add(transReqBF0040001);

			transContent.setTrans_reqDatas(trans_reqDatas);

			String bean2XmlString = transContent.obj2Str(transContent);
			log.info("宝付代付请求报文：" + bean2XmlString);
			String origData = bean2XmlString;

			/**
			 * 加密规则：项目编码UTF-8
			 * 第一步：BASE64 加密
			 * 第二步：商户私钥加密
			 */
			origData =  new String(SecurityUtil.Base64Encode(origData));//Base64.encode(origData);
			String encryptData = RsaCodingUtil.encryptByPriPfxFile(origData,
					keyStorePath, keyStorePassword);

			log.info("宝付代付请求报文加密：" + encryptData);

			// 发送请求
			RequestParams params = new RequestParams();
			params.setMemberId(Integer.parseInt(memberId));
			params.setTerminalId(Integer.parseInt(terminalId));
			params.setDataType(dataType);
			params.setDataContent(encryptData);// 加密后数据
			params.setVersion(TransConstant.version);
			params.setRequestUrl(proxypayUrl);
			SimpleHttpResponse response = BaofooClient.doRequest(params);

			String reslut = response.getEntityString();
			log.info("宝付代付请求返回结果：" + reslut);

			TransContent<TransRespBF0040001> str2Obj = new TransContent<TransRespBF0040001>(dataType);
			/**
			 * 在商户终端正常的情况下宝付同步返回会以密文形式返回,如下：
			 *
			 * 此时要先宝付提供的公钥解密：RsaCodingUtil.decryptByPubCerFile(reslut, pub_key)
			 *
			 * 再次通过BASE64解密：new String(new Base64().decode(reslut))
			 *
			 * 在商户终端不正常或宝付代付系统异常的情况下宝付同步返回会以明文形式返回
			 */
			//明文返回处理可能是报文头参数不正确、或其他的异常导致；
			if (reslut.contains("trans_content")) {
				//明文返回
				//我报文错误处理
				str2Obj = (TransContent<TransRespBF0040001>) str2Obj.str2Obj(reslut, TransRespBF0040001.class);
			} else {
				//密文返回
				//第一步：公钥解密
				reslut = RsaCodingUtil.decryptByPubCerFile(reslut, pub_key);
				//第二步BASE64解密
				reslut = SecurityUtil.Base64Decode(reslut);
				log.info("宝付代付请求返回结果明文"+reslut);
				str2Obj = (TransContent<TransRespBF0040001>) str2Obj.str2Obj(reslut, TransRespBF0040001.class);
			}
			// 业务逻辑判断
			map.put("info",str2Obj.getTrans_head());
			map.put("data",str2Obj.getTrans_reqDatas());
			return map;
		}catch (Exception e){
			log.info("宝付代付请求失败"+e);
		}
		return null;
	}

	/* 
	 * 代付（代发）结果查询
	 */
//	@Override
//	public Map<String, Object> proxyPayQuery(TransReqBF0040002 transReqBF0040002) {
//		String dataType = TransConstant.data_type_xml; // 数据类型 xml/json
//		Map<String, Object> map = new HashMap<String, Object>();
//		try {
//			TransContent<TransReqBF0040002> transContent = new TransContent<TransReqBF0040002>(dataType);
//			List<TransReqBF0040002> trans_reqDatas = new ArrayList<TransReqBF0040002>();
//			trans_reqDatas.add(transReqBF0040002);
//			transContent.setTrans_reqDatas(trans_reqDatas);
//			String bean2XmlString = transContent.obj2Str(transContent);
//			log.info("宝付代付查询请求报文：" + bean2XmlString);
//
//			String origData = bean2XmlString;
//			//origData = Base64.encode(origData);
//			/**
//			 * 加密规则：项目编码UTF-8
//			 * 第一步：BASE64 加密
//			 * 第二步：商户私钥加密
//			 */
//			origData =  new String(SecurityUtil.Base64Encode(origData));//Base64.encode(origData);
//			String encryptData = RsaCodingUtil.encryptByPriPfxFile(origData,keyStorePath, keyStorePassword);
//
//			log.info("宝付代付查询请求加密结果：" + encryptData);
//
//			// 发送请求
//			String requestUrl = baofooProperties.getProxypayQueryUrl();
//			String memberId = baofooProperties.getMerchId(); // 商户号
//			String terminalId = baofooProperties.getTerminalId(); // 终端号
//
//			RequestParams params = new RequestParams();
//			params.setMemberId(Integer.parseInt(memberId));
//			params.setTerminalId(Integer.parseInt(terminalId));
//			params.setDataType(dataType);
//			params.setDataContent(encryptData);// 加密后数据
//			params.setVersion(TransConstant.version);
//			params.setRequestUrl(requestUrl);
//			SimpleHttpResponse response = BaofooClient.doRequest(params);
//
//			String reslut = response.getEntityString();
//			log.info("宝付代付查询请求返回结果：" + reslut);
//			TransContent<TransRespBF0040002> str2Obj = new TransContent<TransRespBF0040002>(dataType);
//			/**
//			 * 在商户终端正常的情况下宝付同步返回会以密文形式返回,如下：
//			 *
//			 * 此时要先宝付提供的公钥解密：RsaCodingUtil.decryptByPubCerFile(reslut, pub_key)
//			 *
//			 * 再次通过BASE64解密：new String(new Base64().decode(reslut))
//			 *
//			 * 在商户终端不正常或宝付代付系统异常的情况下宝付同步返回会以明文形式返回
//			 */
//			if (reslut.contains("trans_content")) {
//				// 我报文错误处理
//				str2Obj = (TransContent<TransRespBF0040002>) str2Obj.str2Obj(reslut,TransRespBF0040002.class);
//			} else {
//				reslut = RsaCodingUtil.decryptByPubCerFile(reslut, pub_key);
//				reslut = SecurityUtil.Base64Decode(reslut);
//				str2Obj = (TransContent<TransRespBF0040002>) str2Obj.str2Obj(reslut,TransRespBF0040002.class);
//			}
//			log.info("宝付代付请求返回结果明文"+reslut);
//			//业务逻辑判断
//			map.put("info",str2Obj.getTrans_head());
//			map.put("data",str2Obj.getTrans_reqDatas());
//			return map;
//		}catch (Exception e){
//			log.info("宝付代付查询失败");
//		}
//		return map;
//	}

	/*
	 * 接受代付（代收）异步通知
	 */
//	@Override
//	public List<TransRespBF40001Async> proxyPayNotify(String reslut) {
//		String dataType = TransConstant.data_type_xml; // 数据类型 xml/json
//		List<TransRespBF40001Async> reqDatas = new ArrayList<TransRespBF40001Async>();
//		try {
//			String pub_key = baofooProperties.getCerFile();//宝付公钥
//			TransContent<TransRespBF40001Async> str2Obj = new TransContent<TransRespBF40001Async>(dataType);
//			// 密文返回
//			// 第一步：公钥解密
//			reslut = RsaCodingUtil.decryptByPubCerFile(reslut, pub_key);
//			// 第二步BASE64解密
//			reslut = SecurityUtil.Base64Decode(reslut);
//			log.info("宝付代付通知明文:"+reslut);
//			str2Obj = (TransContent<TransRespBF40001Async>) str2Obj.str2Obj(reslut, TransRespBF40001Async.class);
//			// 业务逻辑判断
//			reqDatas = str2Obj.getTrans_reqDatas();
//		}catch (Exception e){
//			log.info("宝付代付通知处理错误");
//		}
//		return reqDatas;
//	}

	/* 
	 * 绑卡接口
	 */
	@Override
	public Map<String, Object> bindCard(Map<String, String> request) {
		Map<String, Object> resMap = new HashMap<String, Object>();
		try {
			//报文头
			Map<String, String> headParam = getAuthPayheadParam("01");
			//报文体
			Map<String,Object> commonParam = getCommonparam("01");
			String cardNo = request.get("acc_no");
			if(StringUtils.isNotEmpty(cardNo)){
				//查询卡bin是否存在
				String cardBin = cardNo.substring(0, 6);
				BankCardBinExample example = new BankCardBinExample();
				example.createCriteria().andBankcardNoteEqualTo(Integer.parseInt(cardBin));
				List<BankCardBin> list = bankCardBinMapper.selectByExample(example);
				if(list != null && list.size()==1){
					commonParam.put("acc_no", request.get("acc_no"));//银行卡号
					commonParam.put("trans_id", request.get("trans_id"));//商户订单号
					commonParam.put("id_card_type", "01");//证件类型固定01（身份证）
					commonParam.put("id_card", request.get("id_card"));
					commonParam.put("id_holder", request.get("id_holder"));
					commonParam.put("mobile", request.get("mobile"));
					commonParam.put("valid_date", "");
					commonParam.put("valid_no", "");
//					commonParam.put("pay_code", list.get(0).getBankcardCode());
					commonParam.put("pay_code", list.get(0).getCardCode());
				}else{
					resMap.put("result_code", MapUtil.INTF_ERR_CODE);
					resMap.put("result_info", "不支持的银行");
					return resMap;
				}
			}

			//数据加密
			String data_content = getDataContent(commonParam,headParam.get("data_type"));
			String base64str = SecurityUtil.Base64Encode(data_content);
//			String keyStorePath = baofooProperties.getPfxFile();//商户私钥
//			String keyStorePassword = baofooProperties.getPfxPassword();
//			String pub_key = baofooProperties.getCerFile();//宝付公钥

			data_content = RsaCodingUtil.encryptByPriPfxFile(base64str,keyStorePath, keyStorePassword);
			headParam.put("data_content", data_content);
//			String url =baofooProperties.getAuthpayUrl();
			String PostString  = HttpsUtil.RequestForm(authpayUrl, headParam);
			log.info("宝付直接绑卡请求返回："+ PostString);
			PostString = RsaCodingUtil.decryptByPubCerFile(PostString,pub_key);

			if(PostString.isEmpty()){//判断解密是否正确。如果为空则宝付公钥不正确
				log.info("宝付直接绑卡检查解密公钥是否正确！");
				resMap.put("result_code", MapUtil.INTF_ERR_CODE);
				resMap.put("result_info", "绑卡失败");
				return resMap;
			}
			PostString = SecurityUtil.Base64Decode(PostString);
			log.info("宝付直接绑卡返回查询数据解密结果:"+PostString);

			if(headParam.get("data_type").equals("xml")){
				PostString = JXMConvertUtil.XmlConvertJson(PostString);
				log.info("宝付直接绑卡返回结果转JSON:"+PostString);
			}
			resMap = JXMConvertUtil.JsonConvertHashMap(PostString);//将JSON转化为Map对象。
			log.info("宝付直接绑卡返回结果转换为MAP对象："+resMap);
		}catch (Exception e){
			resMap.put("result_code", MapUtil.INTF_ERR_CODE);
			resMap.put("result_info", "宝付直接绑卡失败");
			return resMap;
		}
		return resMap;
	}

	/* 
	 * 认证支付-预支付
	 */
	@Override
	public Map<String, Object> authPay(Map<String, String> request) {
		Map<String, Object> resMap = new HashMap<String, Object>();
		try {
			//报文头
			Map<String, String> headParam = getAuthPayheadParam("15");
			//报文体
			Map<String,Object> commonParam = getCommonparam("15");
			Map<String,String> clientIp = new HashMap<String,String>();
//			clientIp.put("client_ip", StringUtil.getIpAddr());
			clientIp.put("client_ip", "100.0.0.0");
			commonParam.put("bind_id",request.get("bind_id"));
			commonParam.put("trans_id", request.get("transId"));
			commonParam.put("risk_content", clientIp);
			commonParam.put("txn_amt", request.get("amount"));//金额以分为单位(整型数据)并把元转换成分
			//数据加密
			String data_content = getDataContent(commonParam,headParam.get("data_type"));
			String base64str = SecurityUtil.Base64Encode(data_content);
//			String keyStorePath = baofooProperties.getPfxFile();//商户私钥
//			String keyStorePassword = baofooProperties.getPfxPassword();
//			String pub_key = baofooProperties.getCerFile();//宝付公钥
			data_content = RsaCodingUtil.encryptByPriPfxFile(base64str,keyStorePath, keyStorePassword);
			headParam.put("data_content", data_content);
//			String url =baofooProperties.getAuthpayUrl();
			String PostString  = HttpsUtil.RequestForm(authpayUrl, headParam);
			log.info("宝付认证支付预支付请求返回："+ PostString);

			PostString = RsaCodingUtil.decryptByPubCerFile(PostString,pub_key);

			if(PostString.isEmpty()){//判断解密是否正确。如果为空则宝付公钥不正确
				log.info("宝付认证支付预支付解密公钥是否正确！");
				return null;
			}
			PostString = SecurityUtil.Base64Decode(PostString);
			log.info("宝付认证支付预支付返回查询数据解密结果:"+PostString);

			if(headParam.get("data_type").equals("xml")){
				PostString = JXMConvertUtil.XmlConvertJson(PostString);
				log.info("宝付认证支付预支付返回结果转JSON:"+PostString);
			}
			resMap = JXMConvertUtil.JsonConvertHashMap(PostString);//将JSON转化为Map对象。
			log.info("宝付认证支付预支付返回结果转换为MAP对象："+resMap);
		}catch (Exception e){
			e.printStackTrace();
			log.info("宝付认证支付预支付失败："+e);
			return null;
		}
		return resMap;
	}

	/* 
	 * 认证支付-确认支付
	 */
	@Override
	public Map<String, Object> authPayConfirm(Map<String, String> request) {
		Map<String, Object> resMap = new HashMap<String, Object>();
		try {
			//报文头
			Map<String, String> headParam = getAuthPayheadParam("16");
			//报文体
			Map<String,Object> commonParam = getCommonparam("16");
			commonParam.put("sms_code", request.get("smsCode"));
			commonParam.put("business_no", request.get("businessNo"));
			//数据加密
			String data_content = getDataContent(commonParam,headParam.get("data_type"));
			String base64str = SecurityUtil.Base64Encode(data_content);
//			String keyStorePath = baofooProperties.getPfxFile();//商户私钥
//			String keyStorePassword = baofooProperties.getPfxPassword();
//			String pub_key = baofooProperties.getCerFile();//宝付公钥
			data_content = RsaCodingUtil.encryptByPriPfxFile(base64str,keyStorePath, keyStorePassword);
			headParam.put("data_content", data_content);
//			String url =baofooProperties.getAuthpayUrl();
			String PostString  = HttpsUtil.RequestForm(authpayUrl, headParam);
			log.info("宝付认证支付确认支付请求返回："+ PostString);

			PostString = RsaCodingUtil.decryptByPubCerFile(PostString,pub_key);

			if(PostString.isEmpty()){//判断解密是否正确。如果为空则宝付公钥不正确
				log.info("宝付认证支付确认支付解密公钥是否正确！");
				return null;
			}
			PostString = SecurityUtil.Base64Decode(PostString);
			log.info("宝付认证支付确认支付返回查询数据解密结果:"+PostString);

			if(headParam.get("data_type").equals("xml")){
				PostString = JXMConvertUtil.XmlConvertJson(PostString);
				log.info("宝付认证支付确认支付返回结果转JSON:"+PostString);
			}
			resMap = JXMConvertUtil.JsonConvertHashMap(PostString);//将JSON转化为Map对象。
			log.info("宝付认证支付确认支付返回结果转换为MAP对象："+resMap);
			resMap.put("dataJson",PostString);
		}catch (Exception e){
			log.info("宝付认证支付确认支付失败："+e);
			return null;
		}
		return resMap;
	}

	/* 
	 * 认证支付-订单查询
	 */
	@Override
	public Map<String, Object> authPayQuery(Map<String, String> request) {
		Map<String, Object> resMap = new HashMap<String, Object>();
		try {
			//报文头
			Map<String, String> headParam = getAuthPayheadParam("31");
			//报文体
			Map<String,Object> commonParam = getCommonparam("31");
			commonParam.put("orig_trans_id", request.get("origTransId"));
			commonParam.put("orig_trade_date", request.get("origTransDate"));
			//数据加密
			String data_content = getDataContent(commonParam,headParam.get("data_type"));
			String base64str = SecurityUtil.Base64Encode(data_content);
//			String keyStorePath = baofooProperties.getPfxFile();//商户私钥
//			String keyStorePassword = baofooProperties.getPfxPassword();
//			String pub_key = baofooProperties.getCerFile();//宝付公钥
			data_content = RsaCodingUtil.encryptByPriPfxFile(base64str,keyStorePath, keyStorePassword);
			headParam.put("data_content", data_content);
//			String url =baofooProperties.getAuthpayUrl();
			String PostString  = HttpsUtil.RequestForm(authpayUrl, headParam);
			log.info("宝付认证支付查询请求返回："+ PostString);

			PostString = RsaCodingUtil.decryptByPubCerFile(PostString,pub_key);

			if(PostString.isEmpty()){//判断解密是否正确。如果为空则宝付公钥不正确
				log.info("宝付认证支付查询解密公钥是否正确！");
				return null;
			}
			PostString = SecurityUtil.Base64Decode(PostString);
			log.info("宝付认证支付查询返回查询数据解密结果:"+PostString);

			if(headParam.get("data_type").equals("xml")){
				PostString = JXMConvertUtil.XmlConvertJson(PostString);
				log.info("宝付认证支付查询返回结果转JSON:"+PostString);
			}
			resMap = JXMConvertUtil.JsonConvertHashMap(PostString);//将JSON转化为Map对象。
			log.info("宝付认证支付查询返回结果转换为MAP对象："+resMap);
			resMap.put("dataJson",PostString);
		}catch (Exception e){
			log.info("宝付认证支付查询失败："+e);
			return null;
		}
		return resMap;
	}

	/**
	 * 报文头
	 */
	private Map<String, String> getAuthPayheadParam(String txnSubType){
		Map<String,String> HeadPostParam = new HashMap<String,String>();
//		String memberId = baofooProperties.getMerchId(); // 商户号
//		String terminalId = baofooProperties.getTerminalId(); // 终端号
		HeadPostParam.put("version", "4.0.0.0");
		HeadPostParam.put("member_id", memberId);
		HeadPostParam.put("terminal_id", terminalId);
		HeadPostParam.put("txn_type", "0431");
		HeadPostParam.put("txn_sub_type", txnSubType);
		HeadPostParam.put("data_type", TransConstant.data_type_xml);
		return HeadPostParam;
	}
	/**
	 * 公共参数
	 */
	private Map<String, Object> getCommonparam(String txnSubType){
//		String memberId = baofooProperties.getMerchId(); // 商户号
//		String terminalId = baofooProperties.getTerminalId(); // 终端号
		Map<String,Object> commonParam = new HashMap<String,Object>();
		commonParam.put("txn_sub_type", txnSubType);
		commonParam.put("biz_type", "0000");
		commonParam.put("terminal_id", terminalId);
		commonParam.put("member_id", memberId);
		commonParam.put("trans_serial_no", "TISN"+System.currentTimeMillis());
		String trade_date= DateUtil.now("yyyyMMddHHmmss");//交易日期
		commonParam.put("trade_date", trade_date);
		commonParam.put("additional_info", "附加信息");
		commonParam.put("req_reserved", "保留");
		return commonParam;
	}

	private String getDataContent(Map<String,Object> commonParam,String dataType) throws Exception{
		Map<Object,Object> arrayToObj = new HashMap<Object,Object>();
		String XmlOrJson = "";
		if(("xml").equals(dataType)){
			arrayToObj.putAll(commonParam);
			XmlOrJson = MapToXml.Coverter(arrayToObj,"data_content");
		}else{
			JSONObject jsonObjectFromMap = JSONObject.fromObject(commonParam);
			XmlOrJson = jsonObjectFromMap.toString();
		}
		log.info("宝付认证请求参数："+XmlOrJson);
		return XmlOrJson;
	}
}
